package com.yumeko.boot;

import com.yumeko.mapper.HttpServlet;
import com.yumeko.mapper.Mapper;
import com.yumeko.mapper.RequestProcessor;
import com.yumeko.mapper.Server;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * @program: myTomcat_zhenghao
 * @description:
 * @author: Zheng Hao
 * @create: 2020-02-15 11:17
 */
public class BootStrap {
    //存放server
    private Server server;
    private Mapper mapper =  new Mapper();


    //初始化Server.xml文件
    private void initServer(){
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("server.xml");
        var saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            List<Element> serviceNodes = rootElement.selectNodes("//Service");
            for (int i = 0; i <serviceNodes.size() ; i++) {
                Element element = serviceNodes.get(i);
                //<Connector port="8080"/>
                Element connector = (Element)element.selectSingleNode("Connector");
                String port = connector.attributeValue("port");
                //<Engine/>
                Element Engine = (Element)element.selectSingleNode("Engine");
                //<Host/>
                Element host = (Element)Engine.selectSingleNode("Host");
                String name = host.attributeValue("name");
                String appBase = host.attributeValue("appBase");
                server = new Server(Integer.valueOf(port),name,appBase);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }

    }

    //加载解析web.xml，初始化Servlet
    private void loadServlet(String appBase) {
        try {
            //找到项目根目录例如 D:/intellij/source/myTomcat_zhenghao/src/webapps/demo1
            DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(appBase));
                for(Path path : directoryStream) {
                    //使用nio2提供的walkFileTree查找项目下的文件树
                    Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            //获取到html
                            if (file.toString().endsWith(".html")) {
                                //保存到mapper的静态map
                                mapper.insertStaticMapper(path.getFileName() + "/" + file.getFileName(), file.toUri());
                            }
                            //获取到xml
                            if (file.toString().endsWith(".xml")) {
                                InputStream resourceAsStream = Files.newInputStream(file);
                                var saxReader = new SAXReader();
                                try {
                                    var document = saxReader.read(resourceAsStream);
                                    var rootElement = document.getRootElement();
                                    List<Element> selectNodes = rootElement.selectNodes("//servlet");
                                    for (var i = 0; i < selectNodes.size(); i++) {
                                        var element = selectNodes.get(i);
                                        // <servlet-name>yumeko</servlet-name>
                                        var servletnameElement = (Element) element.selectSingleNode("servlet-name");
                                        var servletName = servletnameElement.getStringValue();
                                        // <servlet-class>com.yumeko.YumekoServlet</servlet-class>
                                        var servletclassElement = (Element) element.selectSingleNode("servlet-class");
                                        var servletClass = servletclassElement.getStringValue();
                                        // 根据servlet-name的值找到url-pattern
                                        var servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                                        // /yumeko
                                        var urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                                        URI uri = new URI(path.toUri()+servletClass.replace(".", "/")+".class");
                                        //实例化外部servlet
                                        MyClassLoader loader = new MyClassLoader(uri);
                                        Class<?> aClass = loader.findClass(servletClass);
                                        HttpServlet httpServlet = (HttpServlet)aClass.getConstructor().newInstance();
                                        //保存到mapper的动态map
                                        mapper.insertDynamicMapper(path.getFileName()+urlPattern,httpServlet);
                                    }
                                } catch (DocumentException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | URISyntaxException e) {
                                    e.printStackTrace();
                                }
                            }
                            return FileVisitResult.CONTINUE;
                        }
                    });
                    System.out.println("-----------------------------------------------------------");
                }
            directoryStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**初始化操作*/
    public void start() {
        //加载server.xml
        initServer();
        // 加载解析相关的配置，web.xml并映射
        loadServlet(server.getAppBase());
        // 定义一个线程池
        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100L;
        var unit = TimeUnit.SECONDS;
        var workQueue = new ArrayBlockingQueue<Runnable>(50);
        var threadFactory = Executors.defaultThreadFactory();
        var handler = new ThreadPoolExecutor.AbortPolicy();
        var threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );
        //多线程改造（使用线程池）
        while (true) {
            try (//服务器套接字等待通过网络进入的请求。 它根据该请求执行某些操作，然后可能将结果返回给请求者
                 var serverSocket = new ServerSocket(server.getPort());
            ) {
                //侦听对此套接字的连接并接受它。
                var socket = serverSocket.accept();
                //创建线程
                var requestProcessor = new RequestProcessor(socket, mapper);
                //使用线程池
                threadPoolExecutor.execute(requestProcessor);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**mytomcat 程序入口*/
    public static void main(String[] args) {
        var bootStrap = new BootStrap();
        bootStrap.start();
    }
}
